package main

import (
	"encoding/json"
	"fmt"
	"os"
	"reflect"
)

type People struct {
	unuse   string //A的反例
	Name    string
	Age     int
	Weight  []int
	Address []byte
	Height  []int
}

type Teacher struct {
	Address string `json:"-"` //T2
	Class   string `json:"teacherClass"`
	Age     int
	Course  string `json:",omitempty"` //T3.1
}
type Student struct {
	T         Teacher //T0
	Specialty string
}
type Student1 struct {
	Teacher   //T1
	Specialty string
}

type functionA func(int, int) int

type Unsupported struct {
	In  chan bool
	Fun functionA
	C   complex64
}

// json 解析示例:
/*
	1.

	Note:
		A:json解析的结构体的成员变量必须是首字母大写
		B:字符串编码为json字符串。角括号"<"和">"会转义为"\u003c"和"\u003e"以避免某些浏览器吧json输出错误理解为HTML。基于同样的原因，"&"转义为"\u0026"。
		C:
		    C1:数组和切片类型的值编码为json数组，
		    C2:[]byte类型的值编码为base64编码字符串，
		    C3:nil切片编码为null
        D:结构体的值编码为json对象。每一个导出字段变成该对象的一个成员,除非:          --> 注意不是匿名结构体字段,比较T0和T1
            D1:字段的标签是"-",示例: `json:"-"`                 //参看T2
            D2:字段是空值，而其标签指定了omitempty选项            //参看T3.0,T3.1
        E:对象默认键字符串是结构体的字段名，但可以在结构体字段的标签里指定。结构体标签值里的"json"键为键名，后跟可选的逗号和选项
            E1:Field int `json:"-"`                     --> 字段被本包忽略
            E2:Field int `json:"myName"`                --> 字段在json里的键为"myName"
            E3:Field int `json:"myName,omitempty"`      --> 字段在json里的键为"myName"且如果字段为空值将在对象中省略掉
            E4:Field int `json:",omitempty"`            --> 字段在json里的键为"Field"（默认值），但如果字段为空值会跳过；注意前导的逗号
            E5:Field int `json:",string"`               --> "string"选项标记一个字段在编码json时应编码为字符串。它只适用于字符串、浮点数、整数类型的字段
        F:通道、复数、函数类型的值不能编码进json。尝试编码它们会导致Marshal函数返回UnsupportedTypeError                --> 参考示例3

*/
func main() {
	var (
		err     error
		theJson []byte
	)
	fmt.Printf("\n Example ---> 示例1 <---\n")
	people := People{
		unuse:   "unuse",                  //A的反例
		Name:    "<zhangsan> &",           //B示例
		Age:     24,                       //A示例
		Weight:  []int{1, 2, 3, 4, 5},     //C1示例
		Address: []byte("china,shenzhen"), //C2示例
		Height:  nil,                      //C3示例

	}
	theJson, err = json.Marshal(people)
	if err != nil {
		fmt.Println("err in json.Marshal(people),reason:", err.Error())
		os.Exit(-1)
	}
	fmt.Printf("%+v\n", string(theJson))
	//结果输出:
	//          {"Name":"\u003czhangsan\u003e \u0026","Age":24,"Weight":[1,2,3,4,5],"Address":"Y2hpbmEsc2hlbnpoZW4=","Height":null}

	fmt.Printf("\n Example ---> 示例2 <---\n")
	student := Student{ //非匿名结构体字段的解析
		T: Teacher{
			Address: "china,shenzhen", //注意Address的tag
			Class:   "grade five",
			Age:     32,
			Course:  "", //T3.0
		},
		Specialty: "It's Very good",
	}
	theJson, err = json.Marshal(student)
	if err != nil {
		fmt.Println("err in json.Marshal(student),reason:", err.Error())
		os.Exit(-1)
	}
	fmt.Printf("非匿名结构体字段的解析:\n\t%+v\n", string(theJson))
	//结果输出:
	//        {"T":{"teacherClass":"grade five","Age":32},"Specialty":"It's Very good"}

	student1 := Student1{ //匿名结构体字段的解析
		Teacher: Teacher{
			Address: "china,shenzhen",
			Class:   "grade five",
			Age:     32,
			Course:  "chinese,math",
		},
		Specialty: "It's Very good",
	}
	theJson, err = json.Marshal(student1)
	if err != nil {
		fmt.Println("err in json.Marshal(student1),reason:", err.Error())
		os.Exit(-1)
	}
	fmt.Printf("匿名结构体字段的解析:\n\t%+v\n", string(theJson))
	//结果输出:
	//        {"teacherClass":"grade five","Age":32,"Course":"chinese,math","Specialty":"It's Very good"}

	fmt.Printf("\n Example ---> 示例3 <---\n")
	unsupported := Unsupported{
		In: make(chan bool, 1),
		Fun: func(a, b int) int {
			return a + b
		},
		C: 3.2 + 12i,
	}
	theJson, err = json.Marshal(unsupported)
	if err != nil {
		fmt.Printf("通道、复数、函数类型 结构体字段的解析:\n\t%+v%+v%+v\n", "err in json.Marshal(unsupported),reason:"+err.Error(), " error type:", reflect.TypeOf(err))
		os.Exit(-1)
	}

}
